﻿using System;
using System.Collections.Generic;
using System.Linq;
using Servicios.Data.Model;
using Servicios.Business.Enumeradores;

namespace Servicios.Business.Modulos
{
    public class Busqueda : List<Busqueda>, IBusqueda
    {
        public Busqueda()
        {

        }

        public new int Count
        {
            get { return this.Count(); }
        }

        #region Implementation of IBusqueda
        public Autor Autor { get; private set; }
        public MaterialBibliografico MaterialBibliografico { get; private set; }
        public Editorial Editorial { get; private set; }
        public TipoMaterialBibliografico TipoMaterialBibliografico { get; private set; }
        public Existencias_por_MatBib ExistenciasPorMatBib { get; private set; }
        public TipoPrestamo TipoPrestamo { get; private set; }
        public Idioma Idioma { get; private set; }
        public Pais Pais { get; private set; }
        public int CantidadExistencias { get; private set; }

        #endregion

        #region Resultados de Busqueda

        public Busqueda GetResult(TipoBusqueda tipoBusqueda, string param)
        {
            switch (tipoBusqueda)
            {
                case TipoBusqueda.Título:
                    return GetResultByTitulo(param);
                case TipoBusqueda.Autor:
                    return GetResultByAutor(param);
                case TipoBusqueda.Tema:
                    return GetResultByTema(param);
                case TipoBusqueda.Todo:
                    return GetResultByAll(param);
                default:
                    return null;
            }
        }
        
        private Busqueda GetResultByAll(string param)
        {
            throw new NotImplementedException("No se ha implementado este método");
        }

        private Busqueda GetResultByTema(string param)
        {
            throw new NotImplementedException();
        }

        private Busqueda GetResultByAutor(string param)
        {
            if (!string.IsNullOrEmpty(param))
                using (var be = new BibliotecaEntities())
                {

                    var query = (from mb in be.MaterialBibliograficoSet
                                 join aus in be.MatBib_por_AutorSet on mb.ID equals aus.MatBibID
                                 join ats in be.AutorSet on aus.AutorID equals ats.ID into Autores
                                 from a in Autores
                                 orderby a.ID
                                 join tipoMB in be.TipoMaterialBibliograficoSet on mb.Bib_TipoMaterialBibliografico.ID equals
                                     tipoMB.ID
                                 join exists in be.Existencias_por_MatBibSet on mb.ID equals
                                     exists.Bib_MaterialBibliografico.ID into Existencias
                                 join ed in be.EditorialSet on mb.Bib_Editorial.ID equals ed.ID into Editorial
                                 where
                                     (a.Nombres.Contains(param) || a.Apellidos.Contains(param)) &&
                                     aus.AutorID == a.ID &&
                                     aus.MatBibID == mb.ID
                                 group new { Autor = a.Apellidos + ", " + a.Nombres }
                                     by new
                                     {
                                         ID = mb.ID,
                                         Titulo = mb.Titulo,
                                         Clasificacion = mb.Clasificacion,
                                         TipoMaterialBibliografico = tipoMB.Nombre,
                                         AnioPublicacion = mb.AnioPublicacion,
                                         NumeroExistencias = Existencias.Count(),
                                         Editorial = Editorial.FirstOrDefault()
                                     }
                                     into result
                                     orderby result.Key.AnioPublicacion descending

                                     select result).ToList();
                    this.Clear();
                    Busqueda nodo;
                    string nomAutores = string.Empty;

                    foreach (var m in query)
                    {
                        nodo = new Busqueda()
                        {
                            MaterialBibliografico = new MaterialBibliografico()
                            {
                                ID = m.Key.ID,
                                Titulo = m.Key.Titulo,
                                Clasificacion = m.Key.Clasificacion,
                                Descripcion = m.Key.TipoMaterialBibliografico,
                                AnioPublicacion = m.Key.AnioPublicacion
                            },
                            TipoMaterialBibliografico = new TipoMaterialBibliografico()
                            {
                                Nombre = m.Key.TipoMaterialBibliografico
                            },
                            Editorial = new Editorial()
                            {
                                Nombre = m.Key.Editorial == null ? string.Empty : m.Key.Editorial.Nombre
                            }
                        };
                        //Garcia Marquez, Gabriel/Vargas Llosa, Mario
                        foreach (var au in m)
                        {
                            nomAutores = au.Autor + " / " + nomAutores;
                        }

                        nomAutores = nomAutores.Substring(0, nomAutores.Length - 2);
                        nodo.Autor = new Autor() { Nombres = nomAutores };
                        nodo.CantidadExistencias = m.Key.NumeroExistencias;

                        this.Add(nodo);
                        nomAutores = string.Empty;
                    }

                }
            return this;
        }

        private Busqueda GetResultByTitulo(string param)
        {
            if (!string.IsNullOrEmpty(param))
                using (var be = new BibliotecaEntities())
                {
                    var query = (from mb in be.MaterialBibliograficoSet
                                 join aus in be.MatBib_por_AutorSet on mb.ID equals aus.MatBibID
                                 join a in be.AutorSet on aus.AutorID equals a.ID
                                 orderby a.ID
                                 join tipoMB in be.TipoMaterialBibliograficoSet on mb.Bib_TipoMaterialBibliografico.ID equals
                                     tipoMB.ID
                                 join exists in be.Existencias_por_MatBibSet on mb.ID equals exists.Bib_MaterialBibliografico.ID
                                     into existencias
                                 join ed in be.EditorialSet on mb.Bib_Editorial.ID equals ed.ID into Editorial



                                 where mb.Titulo.Contains(param) &&
                                       aus.AutorID == a.ID &&
                                       aus.MatBibID == mb.ID
                                 group new { Autor = a.Apellidos + "," + a.Nombres }
                                     by new
                                     {
                                         ID = mb.ID,
                                         Titulo = mb.Titulo,
                                         Clasificacion = mb.Clasificacion,
                                         TipoMaterialBibliografico = tipoMB.Nombre,
                                         AnioPublicacion = mb.AnioPublicacion,
                                         NumeroExistencias = existencias.Count(),
                                         Editorial = Editorial.FirstOrDefault()
                                     }
                                     into result

                                     orderby result.Key.AnioPublicacion descending
                                     select result).ToList();
                    this.Clear();
                    Busqueda nodo;
                    string nomAutores = string.Empty;

                    foreach (var m in query)
                    {
                        nodo = new Busqueda()
                        {
                            MaterialBibliografico = new MaterialBibliografico()
                            {
                                ID = m.Key.ID,
                                Titulo = m.Key.Titulo,
                                Clasificacion = m.Key.Clasificacion,
                                Descripcion = m.Key.TipoMaterialBibliografico,
                                AnioPublicacion = m.Key.AnioPublicacion
                            },
                            TipoMaterialBibliografico = new TipoMaterialBibliografico()
                            {
                                Nombre = m.Key.TipoMaterialBibliografico
                            },
                            Editorial = new Editorial()
                            {
                                Nombre = m.Key.Editorial == null ? string.Empty : m.Key.Editorial.Nombre
                            }
                        };
                        //Garcia Marquez, Gabriel/Vargas Llosa, Mario
                        foreach (var au in m)
                        {
                            nomAutores = au.Autor + " / " + nomAutores;
                        }

                        nomAutores = nomAutores.Substring(0, nomAutores.Length - 2);
                        nodo.Autor = new Autor() { Nombres = nomAutores };
                        nodo.CantidadExistencias = m.Key.NumeroExistencias;

                        this.Add(nodo);
                        nomAutores = string.Empty;
                    }

                }
            return this;
        }

        public Busqueda GetResultByMatBibId(int id)
        {
            using (var be = new BibliotecaEntities())
            {
                var query = (from mb in be.MaterialBibliograficoSet
                             join autorMaterialBibliografico in be.MatBib_por_AutorSet
                                 on mb.ID equals autorMaterialBibliografico.MatBibID
                             join editorial in be.EditorialSet
                                 on mb.Bib_Editorial.ID equals editorial.ID into editorial
                             join tipoMaterial in be.TipoMaterialBibliograficoSet
                                 on mb.Bib_TipoMaterialBibliografico.ID equals tipoMaterial.ID
                             join autor in be.AutorSet
                                 on autorMaterialBibliografico.AutorID equals autor.ID
                             join p in be.PaisSet
                                 on mb.Bib_Pais.ID equals p.ID into pais
                             join i in be.IdiomaSet
                                 on mb.Bib_Idioma.ID equals i.ID into idioma
                             join exists in be.Existencias_por_MatBibSet
                                 on mb.ID equals exists.Bib_MaterialBibliografico.ID into Existencias
                             orderby autor.ID
                             where
                                 mb.ID == id &&
                                 autorMaterialBibliografico.AutorID == autor.ID &&
                                 autorMaterialBibliografico.MatBibID == mb.ID

                             group new
                                       {
                                           Autor = autor.Apellidos + ", " + autor.Nombres
                                       }
                                 by new
                                        {
                                            ID = mb.ID,
                                            Titulo = mb.Titulo,
                                            Clasificacion = mb.Clasificacion,
                                            TipoMaterialBibliografico = tipoMaterial.Nombre,
                                            Editorial = editorial.FirstOrDefault(),
                                            Idioma = idioma.FirstOrDefault(),
                                            Pais = pais.FirstOrDefault(),
                                            NumeroExistencias = Existencias.Count(),
                                        }
                                 into result
                                 select result).ToList();
                this.Clear();
                Busqueda nodo;
                string nomAutores = string.Empty;

                foreach (var m in query)
                {

                    nodo = new Busqueda()
                               {
                                   MaterialBibliografico = new MaterialBibliografico()
                                                               {
                                                                   ID = m.Key.ID,
                                                                   Titulo = m.Key.Titulo,
                                                                   Clasificacion = m.Key.Clasificacion
                                                               },
                                   TipoMaterialBibliografico = new TipoMaterialBibliografico()
                                                                   {
                                                                       Nombre = m.Key.TipoMaterialBibliografico
                                                                   },
                                   Editorial = new Editorial()
                                                   {
                                                       Nombre =
                                                           m.Key.Editorial == null
                                                               ? string.Empty
                                                               : m.Key.Editorial.Nombre
                                                   },
                                   Pais = new Pais()
                                              {
                                                  Nombre = m.Key.Pais == null ? string.Empty : m.Key.Pais.Nombre
                                              },
                                   Idioma = new Idioma()
                                                {
                                                    Nombre = m.Key.Idioma == null ? string.Empty : m.Key.Idioma.Nombre
                                                }
                               };
                    //Garcia Marquez, Gabriel/Vargas Llosa, Mario
                    foreach (var au in m)
                    {
                        nomAutores = au.Autor + " / " + nomAutores;
                    }


                    nomAutores = nomAutores.Substring(0, nomAutores.Length - 2);
                    nodo.Autor = new Autor() { Nombres = nomAutores };
                    nodo.CantidadExistencias = m.Key.NumeroExistencias;

                    this.Add(nodo);
                }
                return this;
            }
        }

        public Busqueda GetExistenciasByMatBibId(int id)
        {
            using (var be = new BibliotecaEntities())
            {
                var query = (from exists in be.Existencias_por_MatBibSet
                             join mb in be.MaterialBibliograficoSet on exists.Bib_MaterialBibliografico.ID equals mb.ID
                             join tp in be.TipoPrestamoSet on exists.Bib_TipoPrestamo.ID equals tp.ID
                             where
                                 mb.ID == id &&
                                 exists.Bib_MaterialBibliografico.ID == mb.ID &&
                                 exists.Habilitado == true
                             select new
                             {
                                 MaterialBibliografico = mb,
                                 Existencia = exists,
                                 TipoPrestamo = tp
                             }).ToList();

                this.Clear();
                foreach (var item in query)
                {
                    this.Add(new Busqueda()
                    {
                        MaterialBibliografico = item.MaterialBibliografico,
                        ExistenciasPorMatBib = item.Existencia,
                        TipoPrestamo = item.TipoPrestamo
                    });
                }

                CantidadExistencias = query.Count();

            }
            return this;
        }

        public Busqueda GetAutoresByPrefix(string param)
        {
            if (!string.IsNullOrEmpty(param))
                using (var bib = new BibliotecaEntities())
                {
                    var query = (from au in bib.AutorSet
                                 where au.Apellidos.ToLower().StartsWith(param.ToLower())
                                      || au.Nombres.ToLower().StartsWith(param.ToLower())
                                 select au).Distinct().ToList();
                    foreach (var au in query)
                    {
                        this.Add(new Busqueda { Autor = au });
                    }
                }
            return this;
        }

        #endregion

        #region Para Paginación de DataSource
        public IEnumerable<Busqueda> GetResult(TipoBusqueda tipoBusqueda, string param, int maximumRows, int startRowIndex)
        {
            return GetResult(tipoBusqueda, param).AsEnumerable().Skip(startRowIndex);
        }

        public int GetResultCount(TipoBusqueda tipoBusqueda, string param)
        {
            return GetResult(tipoBusqueda, param).Count;
        }
        #endregion

    }
}
